';}}
elseif($section==='episodes'){
if($method==='POST'){$id=(int)($_POST['id']??0);$anime=(int)val('anime_id');$num=(int)val('number');$audioLines=preg_split('/\r?\n/',trim(val('streams')),-1,PREG_SPLIT_NO_EMPTY);if($id){db()->prepare('UPDATE episodes SET anime_id=?,season_number=?,number=?,title=?,air_at=?,status=?,robots_index=? WHERE id=?')->execute([$anime,(int)val('season_number','1'),$num,val('title'),val('air_at')?:null,val('status','published'),isset($_POST['robots_index'])?1:0,$id]);$epId=$id;db()->prepare('DELETE FROM streams WHERE episode_id=?')->execute([$id]);}else{db()->prepare('INSERT INTO episodes(anime_id,season_number,number,title,air_at,status,robots_index) VALUES(?,?,?,?,?,?,?)')->execute([$anime,(int)val('season_number','1'),$num,val('title'),val('air_at')?:null,val('status','published'),isset($_POST['robots_index'])?1:0]);$epId=(int)db()->lastInsertId();}foreach($audioLines as $line){$p=array_map('trim',explode('|',$line,4));if(count($p)===4&&filter_var($p[3],FILTER_VALIDATE_URL)){db()->prepare('INSERT INTO streams(episode_id,name,audio,language,url) VALUES(?,?,?,?,?)')->execute([$epId,$p[2],strtolower($p[0]),$p[1],$p[3]]);}}flash('Episode and embed servers saved.');go('admin/episodes');}
if(isset($_GET['delete'])){db()->prepare('DELETE FROM episodes WHERE id=?')->execute([(int)$_GET['delete']]);flash('Episode deleted.');go('admin/episodes');}
if(isset($_GET['new'])||isset($_GET['edit'])){$ep=isset($_GET['edit'])?one('SELECT * FROM episodes WHERE id=?',[(int)$_GET['edit']]):[];$animes=rows('SELECT id,title FROM animes ORDER BY title');$streams=$ep?rows('SELECT * FROM streams WHERE episode_id=? ORDER BY id',[(int)$ep['id']]):[];$text='';foreach($streams as $s)$text.=strtoupper($s['audio']).' | '.($s['language']??'').' | '.$s['name'].' | '.$s['url']."\n";$content='';}
else{$items=rows('SELECT ep.*,a.title AS anime_title FROM episodes ep JOIN animes a ON a.id=ep.anime_id ORDER BY ep.id DESC LIMIT 200');$content='
';}}
elseif($section==='content'){
if($method==='POST'){$id=(int)($_POST['id']??0);$kind=val('kind','page')==='post'?'post':'page';$title=val('title');$slug=slugify(val('slug')?:$title);$data=[$kind,$title,$slug,val('excerpt'),val('content'),val('status','draft'),val('seo_title'),val('seo_description'),val('canonical_url'),isset($_POST['robots_index'])?1:0];if($id){$data[]=$id;db()->prepare('UPDATE content_entries SET kind=?,title=?,slug=?,excerpt=?,content=?,status=?,seo_title=?,seo_description=?,canonical_url=?,robots_index=? WHERE id=?')->execute($data);}else db()->prepare('INSERT INTO content_entries(kind,title,slug,excerpt,content,status,seo_title,seo_description,canonical_url,robots_index,published_at) VALUES(?,?,?,?,?,?,?,?,?,?,IF(?=\'published\',NOW(),NULL))')->execute([...$data,val('status','draft')]);flash('Content saved.');go('admin/content');}
if(isset($_GET['delete'])){db()->prepare('DELETE FROM content_entries WHERE id=?')->execute([(int)$_GET['delete']]);flash('Content removed.');go('admin/content');}
if(isset($_GET['new'])||isset($_GET['edit'])){$a=isset($_GET['edit'])?one('SELECT * FROM content_entries WHERE id=?',[(int)$_GET['edit']]):[];$content='';}
else{$items=rows('SELECT * FROM content_entries ORDER BY updated_at DESC LIMIT 200');$content='
';}}
elseif($section==='importer'){
if($method==='POST'){$query=val('query');if($query){$gql='query ($search:String) { Page(page:1,perPage:10) { media(search:$search,type:ANIME) { id idMal title { english romaji } description seasonYear format status episodes averageScore popularity coverImage { extraLarge large } genres } } }';$ch=curl_init('https://graphql.anilist.co');curl_setopt_array($ch,[CURLOPT_POST=>true,CURLOPT_RETURNTRANSFER=>true,CURLOPT_HTTPHEADER=>['Content-Type: application/json','Accept: application/json'],CURLOPT_POSTFIELDS=>json_encode(['query'=>$gql,'variables'=>['search'=>$query]]),CURLOPT_TIMEOUT=>20,CURLOPT_SSL_VERIFYPEER=>true]);$response=curl_exec($ch);$err=curl_error($ch);curl_close($ch);$j=json_decode((string)$response,true);if(!$j||$err){$error='AniList request failed: '.$err;}else{$m=$j['data']['Page']['media'][0]??null;if(!$m)$error='No match found. Try another title.';else{$title=$m['title']['english']?:($m['title']['romaji']??'Untitled');$slug=slugify($title);$poster=save_anilist_poster((string)($m['coverImage']['extraLarge']??($m['coverImage']['large']??'')));$status=['RELEASING'=>'ongoing','FINISHED'=>'completed','HIATUS'=>'hiatus','CANCELLED'=>'cancelled','NOT_YET_RELEASED'=>'upcoming'][$m['status']??'']??'upcoming';$type=($m['format']??'TV')==='MOVIE'?'Movie':(str_contains((string)($m['format']??''),'ONA')?'ONA':'TV');$synopsis=trim(strip_tags(str_replace([' ',' ',' '],' ',$m['description']??'')));$exists=one('SELECT id FROM animes WHERE anilist_id=?',[(int)$m['id']]);if($exists){db()->prepare('UPDATE animes SET title=?,english_title=?,romaji_title=?,synopsis=?,status=?,type=?,year=?,score=?,poster_path=?,expected_episodes=?,genres=?,updated_at=NOW() WHERE id=?')->execute([$title,$m['title']['english']??null,$m['title']['romaji']??null,$synopsis,$status,$type,$m['seasonYear']??null,isset($m['averageScore'])?$m['averageScore']/10:null,$poster,(int)($m['episodes']??0)?:null,json_encode($m['genres']??[]),$exists['id']]);$error='Updated existing anime: '.$title;}else{db()->prepare('INSERT INTO animes(title,english_title,romaji_title,slug,synopsis,status,type,year,score,poster_path,anilist_id,expected_episodes,genres,published_at) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,NOW())')->execute([$title,$m['title']['english']??null,$m['title']['romaji']??null,$slug,$synopsis,$status,$type,$m['seasonYear']??null,isset($m['averageScore'])?$m['averageScore']/10:null,$poster,(int)$m['id'],(int)($m['episodes']??0)?:null,json_encode($m['genres']??[])]);$error='Imported anime details: '.$title.' (episodes/embeds are added in Episodes & Streams).';}}}}}
$content='
AniList metadata importer
Find a title and import its description, status, score, poster URL and expected episode count. Add episode embed URLs under Episodes & Streams.
';}
admin_shell(ucwords(str_replace('-',' ',$section)),$content);exit;
}
if(!str_starts_with($path,'/admin')&&$path!='/robots.txt'&&$path!='/sitemap.xml')auto_watch_episodes();
/* Public frontend */
if($path==='/robots.txt'){header('Content-Type:text/plain; charset=utf-8');echo "User-agent: *\nAllow: /\nDisallow: /admin\nSitemap: ".url('sitemap.xml')."\n";exit;}
if($path==='/sitemap.xml'){header('Content-Type: application/xml; charset=utf-8');$items=rows('SELECT slug,updated_at FROM animes WHERE robots_index=1 UNION ALL SELECT CONCAT(kind,\'/\',slug),updated_at FROM content_entries WHERE status=\'published\' AND robots_index=1 LIMIT 5000');echo ''.e(url()).'';foreach($items as $i){$loc=str_contains($i['slug'],'/')?url((str_starts_with($i['slug'],'post/')?'posts/':'pages/').substr($i['slug'],strpos($i['slug'],'/')+1)):url('anime/'.$i['slug']);echo ''.e($loc).''.e(date('Y-m-d',strtotime($i['updated_at']))).''; }echo '';exit;}
if($path==='/'){
$featured=one('SELECT * FROM animes WHERE featured=1 ORDER BY updated_at DESC LIMIT 1')??one('SELECT * FROM animes ORDER BY updated_at DESC LIMIT 1');
$slides=rows('SELECT * FROM animes ORDER BY featured DESC,popularity DESC,updated_at DESC LIMIT 3');
$slideData=array_map(static function($x){return ['title'=>$x['english_title']?:$x['title'],'poster'=>$x['poster_path']?:'assets/poster-placeholder.svg','backdrop'=>$x['backdrop_path']?:($x['poster_path']?:''),'url'=>url('anime/'.$x['slug']),'type'=>$x['type'],'year'=>$x['year'],'score'=>$x['score'],'description'=>strip_tags((string)$x['synopsis'])];},$slides);
$latestEpisodes=rows("SELECT ep.*,a.title AS anime_title,a.english_title,a.slug AS anime_slug,a.poster_path,a.type,a.score,a.expected_episodes,(SELECT COUNT(DISTINCT e2.number) FROM episodes e2 JOIN streams s2 ON s2.episode_id=e2.id AND s2.is_enabled=1 WHERE e2.anime_id=a.id AND s2.audio='sub') AS sub_count,(SELECT COUNT(DISTINCT e3.number) FROM episodes e3 JOIN streams s3 ON s3.episode_id=e3.id AND s3.is_enabled=1 WHERE e3.anime_id=a.id AND s3.audio='dub') AS dub_count,(SELECT COUNT(DISTINCT e4.number) FROM episodes e4 JOIN streams s4 ON s4.episode_id=e4.id AND s4.is_enabled=1 WHERE e4.anime_id=a.id AND s4.audio='raw') AS raw_count FROM episodes ep JOIN animes a ON a.id=ep.anime_id WHERE ep.status='published' ORDER BY ep.created_at DESC,ep.id DESC LIMIT 12");
$newOnSite=rows('SELECT * FROM animes ORDER BY COALESCE(published_at,created_at) DESC LIMIT 12');
$upcoming=rows("SELECT * FROM animes WHERE status='upcoming' ORDER BY year DESC,updated_at DESC LIMIT 12");
$trending=rows("SELECT * FROM animes ORDER BY popularity DESC,score DESC LIMIT 10");
$airing=rows("SELECT ep.*,a.title AS anime_title,a.english_title,a.slug AS anime_slug,a.poster_path FROM episodes ep JOIN animes a ON a.id=ep.anime_id WHERE ep.air_at IS NOT NULL ORDER BY ep.air_at ASC LIMIT 8");
$posts=rows("SELECT * FROM content_entries WHERE kind='post' AND status='published' ORDER BY published_at DESC LIMIT 4");
site_header('',setting('site_description','Watch the latest anime episodes free in HD.'),setting('seo_home_index','1')==='1');
echo '
';site_footer();exit;
}
if($path==='/community'){
$posts=rows("SELECT * FROM content_entries WHERE kind='post' AND status='published' ORDER BY published_at DESC LIMIT 40");
site_header('Community','Join the discussion, share your art, and connect with fellow anime fans.',setting('seo_pages_index','1')==='1');
echo '
RE:ANIME COMMUNITY
Community Hub
Join the discussion, share your art, and connect with fellow anime enthusiasts.
';site_footer();exit;
}
if($path==='/schedule'){
$airing=rows("SELECT ep.*,a.title AS anime_title,a.english_title,a.slug AS anime_slug,a.poster_path,a.type,a.score,(SELECT COUNT(*) FROM streams sx WHERE sx.episode_id=ep.id AND sx.is_enabled=1 AND sx.audio='sub') AS sub_count,(SELECT COUNT(*) FROM streams dx WHERE dx.episode_id=ep.id AND dx.is_enabled=1 AND dx.audio='dub') AS dub_count FROM episodes ep JOIN animes a ON a.id=ep.anime_id WHERE ep.air_at IS NOT NULL ORDER BY ep.air_at ASC LIMIT 300");
site_header('Weekly Schedule','Keep track of upcoming anime airing times.',setting('seo_schedule_index','1')==='1');
echo '
';site_footer();exit;
}
if($path==='/browse'||$path==='/search'||$path==='/az-list'||preg_match('#^/az-list/([a-z0-9-])$#i',$path,$azMatch)||preg_match('#^/language/([^/]+)$#',$path,$langMatch)){
$conditions=[];$params=[];$title=$path==='/search'?'Search Anime':'Browse Anime';$index=$path==='/search'?false:setting('seo_archive_index','1')==='1';
$term=trim((string)($_GET['q']??''));if($term!==''){$conditions[]='(title LIKE ? OR english_title LIKE ? OR romaji_title LIKE ?)';array_push($params,'%'.$term.'%','%'.$term.'%','%'.$term.'%');}
foreach(['status','type','year','season','language','country'] as $key){$value=trim((string)($_GET[$key]??''));if($value!==''){$allowed=['status','type','year','season','language','country'];if(in_array($key,$allowed,true)){$conditions[]='`'.$key.'`=?';$params[]=$value;}}}
$genre=trim((string)($_GET['genre']??''));if($genre!==''){$conditions[]='genres LIKE ?';$params[]='%"'.$genre.'"%';}
$audio=trim((string)($_GET['audio']??''));if(in_array($audio,['sub','dub','raw'],true)){$conditions[]="EXISTS(SELECT 1 FROM episodes ep JOIN streams st ON st.episode_id=ep.id WHERE ep.anime_id=animes.id AND st.is_enabled=1 AND st.audio=?)";$params[]=$audio;}
if(isset($azMatch[1])){$letter=strtoupper($azMatch[1]);if($letter==='0')$conditions[]="title REGEXP '^[0-9]'";else{$conditions[]='title LIKE ?';$params[]=$letter.'%';}$title='Anime starting with '.$letter;}
if(isset($langMatch[1])){$conditions[]='language=?';$params[]=str_replace('-',' ',$langMatch[1]);$title='Anime in '.ucwords(str_replace('-',' ',$langMatch[1]));}
if($path==='/az-list')$title='Anime A–Z list';
$sorts=['trending'=>'popularity DESC,score DESC','score'=>'score DESC,updated_at DESC','year'=>'year DESC,title ASC','title'=>'title ASC','recent'=>'updated_at DESC'];$sort=(string)($_GET['sort']??'recent');$order=$sorts[$sort]??$sorts['recent'];
$where=$conditions?' WHERE '.implode(' AND ',$conditions):'';$countQuery=db()->prepare('SELECT COUNT(*) FROM animes'.$where);$countQuery->execute($params);$count=(int)$countQuery->fetchColumn();
$items=rows('SELECT * FROM animes'.$where.' ORDER BY '.$order.' LIMIT 60',$params);
$availableGenres=[];foreach(rows('SELECT genres FROM animes WHERE genres IS NOT NULL LIMIT 1000') as $gr){$decoded=json_decode((string)$gr['genres'],true);if(is_array($decoded))foreach($decoded as $g){$g=trim((string)$g);if($g!=='')$availableGenres[$g]=1;}}$availableGenres=array_keys($availableGenres);sort($availableGenres,SORT_NATURAL|SORT_FLAG_CASE);
site_header($title,'Search and browse anime by title, status, format, genre and year.',$index);
echo '
DISCOVER
'.e($title).'
Search anime and refine the results using filters.
No anime found. Try changing your search or filters.
';echo '
';site_footer();exit;
}
if($path==='/watchlist/items'){header('Content-Type: application/json; charset=utf-8');$ids=$_GET['ids']??[];if(!is_array($ids))$ids=[];$ids=array_slice(array_values(array_unique(array_filter(array_map('intval',$ids)))),0,100);if(!$ids){echo '[]';exit;}$marks=implode(',',array_fill(0,count($ids),'?'));$items=rows("SELECT id,title,english_title,slug,poster_path,type,status,score FROM animes WHERE id IN ($marks)",$ids);$out=[];foreach($items as $a)$out[]=['id'=>(string)$a['id'],'title'=>$a['english_title']?:$a['title'],'url'=>url('anime/'.$a['slug']),'poster'=>$a['poster_path']?:url('assets/poster-placeholder.svg'),'type'=>$a['type'],'status'=>$a['status'],'score'=>$a['score']];echo json_encode($out,JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE);exit;}
if($path==='/watchlist'){site_header('Watchlist','Your saved anime',false);echo '
My Watchlist
Saved on this device.
No anime saved yet.
';site_footer();exit;}
if($path==='/posts'){site_header('Posts','Anime news and updates',setting('seo_posts_index','1')==='1');$items=rows("SELECT * FROM content_entries WHERE kind='post' AND status='published' ORDER BY published_at DESC LIMIT 30");echo '
';site_footer();exit;}
if(preg_match('#^/anime/([^/]+)$#',$path,$m)){$a=one('SELECT * FROM animes WHERE slug=? LIMIT 1',[$m[1]]);if(!$a){http_response_code(404);site_header('Not found','Anime not found',false);echo '
Anime not found
';site_footer();exit;}$eps=rows("SELECT * FROM episodes WHERE anime_id=? AND status='published' ORDER BY season_number,number",[$a['id']]);$desc=strip_tags((string)$a['synopsis']);if(function_exists('mb_strimwidth'))$desc=mb_strimwidth($desc,0,300);else$desc=substr($desc,0,300);site_header($a['seo_title']?:($a['english_title']?:$a['title']),$a['seo_description']?:$desc,(bool)$a['robots_index'],$a['canonical_url']);$genres=json_decode((string)$a['genres'],true)?:[];$audios=rows('SELECT DISTINCT audio FROM streams s JOIN episodes ep ON ep.id=s.episode_id WHERE ep.anime_id=? AND s.is_enabled=1',[$a['id']]);echo '
Episodes will appear after generating them in Admin → Importer.
';echo '
';site_footer();exit;}
if(preg_match('#^/watch/([^/]+)/([0-9]+)/([0-9]+)$#',$path,$m)){
$a=one('SELECT * FROM animes WHERE slug=?',[$m[1]]);
$ep=$a?one("SELECT * FROM episodes WHERE anime_id=? AND season_number=? AND number=? AND status='published'",[$a['id'],(int)$m[2],(int)$m[3]]):null;
if(!$a||!$ep){http_response_code(404);site_header('Episode not found','',false);echo '
Episode not found
';site_footer();exit;}
$streams=rows('SELECT * FROM streams WHERE episode_id=? AND is_enabled=1 ORDER BY sort_order,id',[$ep['id']]);
$siblings=rows("SELECT * FROM episodes WHERE anime_id=? AND status='published' ORDER BY season_number,number",[$a['id']]);
$epIndex=0;foreach($siblings as $k=>$candidate){if((int)$candidate['id']===(int)$ep['id']){$epIndex=$k;break;}}
$previous=$siblings[$epIndex-1]??null;$next=$siblings[$epIndex+1]??null;
$title=$ep['seo_title']?:($a['title'].' - Episode '.$ep['number']);
site_header($title,$ep['seo_description']?:('Watch '.$title),(bool)$ep['robots_index'],$ep['canonical_url']);
$poster=$a['poster_path']?:'assets/poster-placeholder.svg';$genres=json_decode((string)$a['genres'],true)?:[];$streamGroups=[];
foreach($streams as $stream){$key=strtolower((string)($stream['audio']?:'sub'));$streamGroups[$key][]=$stream;}
echo '
';
foreach(rows('SELECT * FROM animes WHERE id<>? ORDER BY popularity DESC,updated_at DESC LIMIT 6',[$a['id']]) as $related)card($related);
echo '
';site_footer();exit;}
if(preg_match('#^/(pages|posts)/([^/]+)$#',$path,$m)){$kind=$m[1]==='posts'?'post':'page';$entry=one('SELECT * FROM content_entries WHERE kind=? AND slug=? AND status=\'published\'',[$kind,$m[2]]);if($entry){site_header($entry['seo_title']?:$entry['title'],$entry['seo_description']?:$entry['excerpt'],(bool)$entry['robots_index'],$entry['canonical_url']);echo '
COMMENTS
0Join the discussion and share your thoughts.
Comments are not enabled in this PHP version yet.